﻿using System;
using System.Collections;
using System.DirectoryServices;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Win32;

namespace Framework
{
    public class IISHelper
    {
        private static readonly DirectoryEntry IISDe = new DirectoryEntry("IIS://localhost/W3SVC");

        //判断 IIS是否安装
        public static bool IsIISSetup
        {
            get
            {
                object obj =
                    Registry.GetValue(
                        @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\Oc Manager\Subcomponents",
                        "iis_inetmgr", "0");
                if (obj == null) return false;

                if (obj.ToString().Equals("1"))
                    return true;
                return false;
            }
        }

        ///<summary>
        /// Get The Location IIS WebServers Information
        ///</summary>
        ///<returns></returns>
        public static Hashtable GetLocationIIsWebServers()
        {
            var result = new Hashtable();
            GetWebSiteInfo(ref result);
            return result;
        }

        /// <summary>
        /// 获取服务器IIS版本
        /// </summary>
        /// <param name="domainName"></param>
        /// <returns></returns>
        public static WebServerTypes GetIISServerType(string domainName)
        {
            if (string.IsNullOrEmpty(domainName))
            {
                domainName = "LOCALHOST";
            }
            string path = "IIS://" + domainName + "/W3SVC/INFO";
            DirectoryEntry entry;
            try
            {
                entry = new DirectoryEntry(path);
            }
            catch
            {
                return WebServerTypes.Unknown;
            }
            int num;
            try
            {
                num = (int)entry.Properties["MajorIISVersionNumber"].Value;
            }
            catch
            {
                return WebServerTypes.IIS5;
            }
            switch (num)
            {
                case 6:
                    return WebServerTypes.IIS6;

                case 7:
                    return WebServerTypes.IIS7;
            }
            return WebServerTypes.IIS6;
        }

        ///<summary>
        /// Create a new IIS Webserver
        ///</summary>
        ///<param name="webServerName">webserver name</param>
        ///<param name="path">webserver directory path</param>
        ///<param name="port">access port</param>
        public static void CreateNewIIsWebServer(string webServerName, string path, int port)
        {
            int siteId = GetWebSiteInfo(port);
            using (var site = (DirectoryEntry)IISDe.Invoke("Create", "IIsWebServer", siteId))
            {
                site.Invoke("Put", "ServerComment", webServerName);
                site.Invoke("Put", "KeyType", "IIsWebServer");
                site.Invoke("Put", "ServerBindings", ":" + port.ToString(CultureInfo.InvariantCulture) + ":");
                site.Invoke("Put", "ServerState", 2);
                site.Invoke("Put", "FrontPageWeb", 1);
                site.Invoke("Put", "DefaultDoc", "Default.aspx");
                site.Invoke("Put", "SecureBindings", ":443:");
                site.Invoke("Put", "ServerAutoStart", 1);
                site.Invoke("Put", "ServerSize", 1);
                site.Invoke("SetInfo");
                using (DirectoryEntry siteVDir = site.Children.Add("Root", "IISWebVirtualDir"))
                {
                    siteVDir.Properties["AppIsolated"][0] = 2;
                    siteVDir.Properties["Path"][0] = path;
                    siteVDir.Properties["AccessFlags"][0] = 513;
                    siteVDir.Properties["FrontPageWeb"][0] = 1;
                    //siteVDir.Properties["AppRoot"][0] = "LM/W3SVC/" + siteID + "/"+webServerName;
                    siteVDir.Properties["AppFriendlyName"][0] = webServerName;
                    siteVDir.Invoke("AppCreate", true);
                    siteVDir.CommitChanges();
                }
                site.CommitChanges();
            }
        }

        ///<summary>
        /// Create a new virtual directory
        ///</summary>
        ///<param name="website">webserver name</param>
        ///<param name="dirName">virtual directory name</param>
        ///<param name="properties">virtual dirctory properties</param>
        public static void CreateNewVirtualDir(string website, string dirName, System.Data.PropertyCollection properties)
        {
            if (GetVirtualDir(website, dirName)) throw new Exception(" The Virtual Dir is alread existed");
            using (DirectoryEntry de = GetWebSiteInfo(website))
            {
                using (DirectoryEntry vde = de.Children.Add(dirName, "IIsWebVirtualDir"))
                {
                    vde.CommitChanges();
                    de.CommitChanges();
                    UpdateVDirInfo(vde, ref properties);
                    vde.Invoke("AppCreate", true);
                    vde.CommitChanges();
                    de.CommitChanges();
                }
            }
        }

        ///<summary>
        /// Get Common virtual directory setting通用的虚拟目录设置
        ///</summary>
        ///<param name="path">virtual directory path</param>
        ///<param name="vdir">virtual directory name</param>
        ///<returns></returns>
        public static System.Data.PropertyCollection GetDefaultVirtualDirSetting(string path, string vdir)
        {
            var vProperty = new System.Data.PropertyCollection
                                {
                                    {"AccessRead", true},
                                    {"AccessExecute", false},
                                    {"AuthBasic", true},
                                    {"AuthNTLM", true},
                                    {"ContentIndexed", true},
                                    {"EnableDefaultDoc", true},
                                    {"EnableDirBrowsing", false},
                                    {"AccessSSL", false},
                                    {"AccessScript", false},
                                    {"DefaultDoc", "Default.aspx"},
                                    {"Path", path},
                                    {"AppIsolated", 2},
                                    {"AppFriendlyName", vdir},
                                    {"AccessFlags", 513},
                                    {"FrontPageWeb", 1}
                                };
            //vProperty.Add("AnonymousUserName","");
            //vProperty.Add("AnonymousUserPass","");
            //vProperty.Add("DontLog", true);
            //vProperty.Add("AppRoot", "LM/W3SVC/" + siteID + "/" + vdir);
            return vProperty;
        }

        ///<summary>
        /// Delete the virtual directory in the WebServer
        ///</summary>
        ///<param name="website">webserver name</param>
        ///<param name="vdir">virtual directory name</param>
        public static void DeleteVirtualDir(string website, string vdir)
        {
            if (!GetVirtualDir(website, vdir)) throw new Exception(" The virtual directory don't exist in the website");
            using (DirectoryEntry de = GetWebSiteInfo(website))
            {
                foreach (DirectoryEntry sub in de.Children)
                {
                    if (sub.Name == vdir)
                    {
                        de.Invoke("Delete", new object[] { sub.SchemaClassName, vdir });
                        de.CommitChanges();
                    }
                }
            }
        }


        private static void UpdateVDirInfo(DirectoryEntry newDe, ref System.Data.PropertyCollection properties)
        {
            //newDE.Properties["AnonyMousUserName"][0] = properties["AnonymousUserName"].ToString();
            //newDE.Properties["AnonymousUserPass"][0] = properties["AnonymousUserPass"].ToString();
            newDe.Properties["AccessRead"][0] = (bool)properties["AccessRead"];
            newDe.Properties["AccessExecute"][0] = (bool)properties["AccessExecute"];
            newDe.Properties["AuthBasic"][0] = (bool)properties["AuthBasic"];
            newDe.Properties["AuthNTLM"][0] = (bool)properties["AuthNTLM"];
            newDe.Properties["ContentIndexed"][0] = (bool)properties["ContentIndexed"];
            newDe.Properties["EnableDefaultDoc"][0] = (bool)properties["EnableDefaultDoc"];
            newDe.Properties["EnableDirBrowsing"][0] = (bool)properties["EnableDirBrowsing"];
            newDe.Properties["AccessSSL"][0] = (bool)properties["AccessSSL"];
            newDe.Properties["AccessScript"][0] = (bool)properties["AccessScript"];
            newDe.Properties["DefaultDoc"][0] = properties["DefaultDoc"].ToString();
            newDe.Properties["Path"][0] = properties["Path"].ToString();
            newDe.Properties["AppIsolated"][0] = (int)properties["AppIsolated"];
            newDe.Properties["AppFriendlyName"][0] = properties["AppFriendlyName"].ToString();
            newDe.Properties["AccessFlags"][0] = (int)properties["AccessFlags"];
            newDe.Properties["FrontPageWeb"][0] = (int)properties["FrontPageWeb"];
            //newDE.Properties["DontLog"][0] = (bool)properties["DontLog"];
            //newDE.Properties["AppRoot"][0] = properties["AppRoot"].ToString();
        }

        public static bool GetVirtualDir(string webSite, string dirName)
        {
            bool result = false;
            using (DirectoryEntry de = GetWebSiteInfo(webSite))
            {
                if (de != null)
                {
                    if (de.Children.Cast<DirectoryEntry>().Any(subVd => subVd.SchemaClassName == "IIsWebVirtualDir" && subVd.Name == dirName))
                    {
                        result = true;
                    }
                }
            }
            return result;
        }

        private static void GetWebSiteInfo(ref Hashtable webServer)
        {
            DirectoryEntries des = IISDe.Children;
            foreach (DirectoryEntry subDe in des)
            {
                if (subDe.SchemaClassName == "IIsWebServer")
                {
                    webServer.Add(subDe.Properties["ServerComment"].Value.ToString(), subDe.Name);
                }
            }
        }

        private static DirectoryEntry GetWebSiteInfo(string website)
        {
            DirectoryEntries des = IISDe.Children;
            DirectoryEntry result = (from DirectoryEntry subDe in des where subDe.SchemaClassName == "IIsWebServer" && subDe.Properties["ServerComment"].Value.ToString() == website select subDe.Children.Find("Root", "IIsWebVirtualDir")).FirstOrDefault();
            return result;
        }

        private static int GetWebSiteInfo(int port)
        {
            int result = 1;
            DirectoryEntries des = IISDe.Children;
            foreach (DirectoryEntry subDe in des)
            {
                if (subDe.SchemaClassName == "IIsWebServer")
                {
                    int i;
                    if ((i = Convert.ToInt32(subDe.Name)) >= result)
                    {
                        result = i + 1;
                    }
                    if (subDe.Properties["ServerBindings"][0].ToString() == ":" + port.ToString(CultureInfo.InvariantCulture) + ":")
                    {
                        throw new Exception(" The port is already used");
                    }
                }
            }
            return result;
        }
        public static void DelSite(string siteName)
        {
            string siteNum = GetWebSiteNum(siteName);
            string siteEntPath = String.Format("IIS://{0}/w3svc/{1}", "localhost", siteNum);
            var siteEntry = new DirectoryEntry(siteEntPath);
            string rootPath = String.Format("IIS://{0}/w3svc", "localhost");
            var rootEntry = new DirectoryEntry(rootPath);
            rootEntry.Children.Remove(siteEntry);
            rootEntry.CommitChanges();
        }
        public static string GetWebSiteNum(string siteName)
        {
            var regex = new Regex(siteName);
            string entPath = String.Format("IIS://{0}/w3svc", "localhost");
            var ent = new DirectoryEntry(entPath);
            foreach (DirectoryEntry child in ent.Children)
            {
                if (child.SchemaClassName == "IIsWebServer")
                {
                    string tmpStr;
                    if (child.Properties["ServerBindings"].Value != null)
                    {
                        tmpStr = child.Properties["ServerBindings"].Value.ToString();
                        if (regex.Match(tmpStr).Success)
                        {
                            return child.Name;
                        }
                    }
                    if (child.Properties["ServerComment"].Value != null)
                    {
                        tmpStr = child.Properties["ServerComment"].Value.ToString();
                        if (regex.Match(tmpStr).Success)
                        {
                            return child.Name;
                        }
                    }
                }
            }
            return "没有找到要删除的站点";
        }

        public static void ModifyScriptMaps(string siteName, ArrayList list)
        {
            string siteNum = GetWebSiteNum(siteName);
            string siteEntPath = String.Format("IIS://{0}/w3svc/{1}", "localhost", siteNum);
            var siteEntry = new DirectoryEntry(siteEntPath);
            var mappings = (Object[])siteEntry.InvokeGet("ScriptMaps");
            var list2 = new ArrayList();
            foreach (string s in mappings)
            {
                if (!list.Contains(s))
                {
                    list2.Add(s);
                }
            }
            list2.AddRange(list);
            //ScriptMaps更改属性值
            siteEntry.Properties["ScriptMaps"].Value = list2.ToArray();
            siteEntry.CommitChanges();
        }
        public static ArrayList AddScriptArray(string[] array)
        {
            var list = new ArrayList();
            foreach (string t in array)
            {
                list.Add(t + @",c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll,5,GET,HEAD,POST,DEBUG"); //默认5代表检查索引，1不检查
            }
            return list;
        }
    }
    public enum WebServerTypes
    {
        Unknown,
        IIS5,
        IIS6,
        IIS7
    }
}